/*
 * @Author: wangchao
 * @Date: 2024-08-27 13:19:12
 * @LastEditors: wangchao
 * @LastEditTime: 2024-10-04 14:54:17
 * @FilePath: \JD-RTT-Driver\small_modbus_tcp\lite_mb_master.c
 * @Description:
 * Copyright (c) 2024 by Bingshan Guardian, All Rights Reserved.
 */

#include "stdio.h"
#include "string.h"
#include "board.h"
#include "lite_mb.h"
#include "lb_virtualIO.h"
#include "u_params.h"

#define DBG_TAG "LITE"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

typedef enum
{
    STATE_PING,
    STATE_KILL_THREAD,
    STATE_CONNECT,
    STATE_RECONNECT,
} lite_mb_state;

#define BMS_HEART_BEAT_ADDR 2011
static rt_mutex_t lite_master_mux = RT_NULL;

lite_mb_state current_lite_mb_state = STATE_PING;

static lite_mb_t modbus_tcp_master = {0};
static rt_bool_t lite_mb_master_startup = RT_FALSE;
static rt_bool_t connected = RT_FALSE;

rt_bool_t pcs_line_state = RT_FALSE;
rt_bool_t pcs_ping_state = RT_FALSE;

rt_bool_t pcs_ip_change = RT_FALSE;
static char pcs_ip_addr[15] = {0};
static char pcs_ip_port[4] = {0};
static rt_uint16_t pcs_slave_id = 0x1;

static uint8_t temp_buff[2];
rt_uint16_t pcs_com_error_count = 0;

static void lite_modbus_tcp_master_thread_entry(void* param)
{
    lite_mb_t* smb_master = param;
    int rc = 0;
    LOG_I("CREATE PCS MASTER THREAD");
    // 初始化Modbus主机
    mb_init(smb_master, MODBUS_CORE_TCP, mb_port_rtsocket_create(MODBUS_DEVICE_MASTER, pcs_ip_addr, pcs_ip_port));
    mb_set_slave(smb_master, pcs_slave_id);

    while (1)
    {
        if (!connected)
        {
            rc = mb_connect(smb_master);
            if (rc >= MODBUS_OK)
            {
                LOG_I("lite modbus tcp connected.");
                connected = RT_TRUE;
                lite_mb_master_startup = RT_TRUE;
                pcs_line_state = RT_TRUE;
            }
            else
            {
                LOG_E("Connection failed, retrying...");
                rt_thread_mdelay(1000);  // 延迟5秒再试
                continue;
            }
        }
        //
        if (connected)
        {
            // --------------- READ F03 From 1#正极泵---------------
            rt_mutex_take(lite_master_mux, RT_WAITING_FOREVER);
            rc = mb_read_registers(smb_master, BMS_HEART_BEAT_ADDR, 1, (uint16_t*)temp_buff);
            rt_mutex_release(lite_master_mux);
            if (rc >= MODBUS_OK)
            {
                pcs_com_error_count = 0;
                // LOG_I("PCS HB...");
            }
            else
            {
                pcs_com_error_count++;
                if (pcs_com_error_count > 5)
                {
                    pcs_line_state = RT_FALSE;
                    current_lite_mb_state = STATE_KILL_THREAD;
                    connected = RT_FALSE;
                    lite_mb_master_startup = RT_FALSE;
                    goto PCS_EXIT;
                }
            }
            rt_thread_mdelay(2000);
        }
    }
PCS_EXIT:
    LOG_E("PCS ERROR");
}

int lite_mb_master_write_to_slave(int slave_id, int reg, int val)
{
    int rc = MODBUS_FAIL_HANDLE;

    if (lite_mb_master_startup)
    {
        rt_mutex_take(lite_master_mux, RT_WAITING_FOREVER);
        lite_mb_t* smb_master = &modbus_tcp_master;
        // mb_error_recovery(smb_master);
        // mb_set_slave(smb_master, slave_id);
        rc = mb_write_register(smb_master, reg, val);
        if (rc >= MODBUS_OK)
        {
            LOG_I("BMS -> PCS OK, ADDR:%d VAL:%d", reg, val);
            rt_mutex_release(lite_master_mux);
            return rc;
        }
        else
        {
            LOG_E("BMS -> PCS ERROR: %d ", rc);
        }
        connected = RT_FALSE;
        lite_mb_master_startup = RT_FALSE;
        rt_mutex_release(lite_master_mux);
    }
    return rc;
}

int control_pcs_device(rt_uint16_t reg, rt_int16_t val)
{
    return lite_mb_master_write_to_slave(pcs_slave_id, reg, val);
}

extern rt_bool_t user_app_ping(char* target_name);

rt_uint8_t error_check_count = 0;

void read_pcs_device_net_data(void)
{
    if (get_app_params(55) > 255 || get_app_params(55) < 1)
    {
        pcs_slave_id = 1;
    }
    else
    {
        pcs_slave_id = get_app_params(55);
    }
    // Read PCS IP ADDRESS
    rt_sprintf(pcs_ip_addr, "%d.%d.%d.%d", get_app_params(56), get_app_params(57), get_app_params(58), get_app_params(59));
    rt_sprintf(pcs_ip_port, "%d", get_app_params(60));
    //
    LOG_I("PCS SID:%d IP:%s Port:%s", pcs_slave_id, pcs_ip_addr, pcs_ip_port);
}

int pcs_mbtcp_master_thread_entry(void *params)
{
    rt_thread_t tid = RT_NULL;
    //
    read_pcs_device_net_data();
    //
    lite_master_mux = rt_mutex_create("lite_master_mux", RT_IPC_FLAG_PRIO);
    for (;;)
    {
        rt_thread_mdelay(1000);

        if (pcs_ip_change)
        {
            read_pcs_device_net_data();
            pcs_ip_change = RT_FALSE;
        }

        switch (current_lite_mb_state)
        {
            case STATE_PING:
                if (user_app_ping(pcs_ip_addr))
                {
                    pcs_ping_state = RT_TRUE;
                    current_lite_mb_state = STATE_CONNECT;
                }
                else
                {
                    // error_check_count++;
                    pcs_ping_state = RT_FALSE;
                    LOG_E("ping: not found available network interface device.");
                }
                break;
            case STATE_CONNECT:
                if (tid == RT_NULL)
                {
                    tid = rt_thread_create("master", lite_modbus_tcp_master_thread_entry, &modbus_tcp_master, 2048, 16, 20);
                    if (tid != RT_NULL)
                    {
                        rt_thread_startup(tid);
                    }
                }
                break;
            case STATE_KILL_THREAD:
                tid = RT_NULL;
                LOG_W("PCS MASTER KILLED");
                rt_thread_mdelay(3500);
                current_lite_mb_state = STATE_PING;
                break;
            default:
                break;
        }
    }
    return 0;
}

int bms_pcs_mbtcp_master_thread(void)
{
    rt_thread_t thread_id = RT_NULL;

    thread_id = rt_thread_create("pcs", (void (*)(void*))pcs_mbtcp_master_thread_entry, RT_NULL, 2048, 15, 10);
    if (thread_id != RT_NULL)
    {
        rt_thread_startup(thread_id);
    }
    else
    {
        goto __exit;
    }
    return RT_EOK;

__exit:
    if (thread_id)
        rt_thread_delete(thread_id);
    return RT_ERROR;
}
